package xj.graph2d.template;

import static javax.swing.SwingConstants.CENTER;
import static javax.swing.SwingConstants.VERTICAL;
import static xj.graph2d.template.VisualClassTemplate.NODE_COLOR;
import static xj.graph2d.template.VisualClassTemplate.NODE_FONT;
import static xj.graph2d.template.VisualClassTemplate.OPER_BG;
import static xj.graph2d.template.VisualClassTemplate.OPER_FG;

import java.awt.Color;
import java.util.Map;

import xj.graph2d.ArrowAttr;
import xj.graph2d.CompoundDrawShape;
import xj.graph2d.DrawAttr;
import xj.graph2d.DrawShape;
import xj.graph2d.DrawShapeConstants;
import xj.graph2d.EllipseShape;
import xj.graph2d.GraphEdgeBase;
import xj.graph2d.GraphNodeBase;
import xj.graph2d.LineShape;
import xj.graph2d.TextShape;
import xj.graph2d.shapes.BoxLabel;
import xj.graph2d.shapes.CompartmentalRoundRectangleShape;
import xj.graph2d.shapes.CubicCurveSelfLoop;
import xj.graph2d.shapes.CubicCurveShape;
import xj.graph2d.shapes.GraphEdgeShape;
import xj.graph2d.shapes.OrthogonalLineShape;
import xj.graph2d.shapes.PolyCurveSelfLoop;
import xj.graph2d.shapes.PolyCurveShape;
import xj.graph2d.shapes.QuadCurveShape;
import xj.graph2d.shapes.RectangularShape;
import xj.graph2d.shapes.ShapeConstants;
import xj.graph2d.shapes.block.BlockShape;
import xj.graph2d.shapes.block.SimpleStatementShape;
import xj.graph2d.shapes.uml.CompoundStateShape;
import xj.graph2d.shapes.uml.OrthogonalStateShape;
import xj.graph2d.shapes.uml.SimpleStateShape;
import xj.graph2d.shapes.uml.UMLStateUtil;
import xj.graph2d.shapes.uml.UMLUtil;
import xj.graph2d.template.uml.UMLStateModelListener;
import xj.graph2d.template.uml.UMLTransitionModelListener;
import xj.model.uml.HyperState;
import xj.model.uml.OrthogonalState;
import xj.model.uml.State;
import xj.model.uml.StateMachine;
import xj.model.uml.SubmachineState;
import xj.model.uml.Transition;

public class UMLStateDiagramTemplate 
  extends UMLTemplate {

  // State Machine Diagram

  static String[][] stateNodeEdgeToolNames = {
    // TOP_SIDE
    { "Transition1-1-Popup", "Transition1-2-Popup",  
      "Transition2-1-Popup", "Transition2-2-Popup",}, 

    // BOTTOM_SIDE 
    { "Transition1-3-Popup", "Transition1-4-Popup", 
      "Transition2-3-Popup", "Transition2-4-Popup",},  

    // LEFT_SIDE
    { "Transition1-5-Popup", "Transition1-6-Popup", 
      "Transition2-5-Popup", "Transition2-6-Popup",},  

    // RIGHT_SIDE
    { "Transition1-7-Popup", "Transition1-8-Popup", 
      "Transition2-7-Popup", "Transition2-8-Popup",},  
  };

  static String[][] initStateNodeEdgeToolNames = {
    // TOP_SIDE
    { "Transition1-1-Popup", "Transition2-1-Popup", },

    // BOTTOM_SIDE 
    { "Transition1-4-Popup", "Transition2-4-Popup", },  

    // LEFT_SIDE
    { "Transition1-6-Popup", "Transition2-6-Popup", },  

    // RIGHT_SIDE
    { "Transition1-7-Popup", "Transition2-7-Popup", },
  };

  static String[][] finalStateNodeEdgeToolNames = {
    // TOP_SIDE
    { "Transition1-2-Popup", "Transition2-2-Popup", }, 

    // BOTTOM_SIDE 
    { "Transition1-3-Popup", "Transition2-3-Popup", },

    // LEFT_SIDE
    { "Transition1-5-Popup", "Transition2-5-Popup", },

    // RIGHT_SIDE
    { "Transition1-8-Popup", "Transition2-8-Popup", },  
  };

  static String[][] stateDiagramGapToolNames = {
    { "StateMachine", "State1", "State2", "State3", },
    { "CompoundState1", "CompoundState2", "OrthogonalState1", "OrthogonalState2", },
    { "InitialState", "EntryState", "ExitState", "FinalState", },
    { "DeepHistory", "ShallowHistory", "JunctionState", "ChoiceState", },
  };

  static String[] transEdgeShapeNames = {
    "Transition-Shape1", "Transition-Shape2", "Transition-Shape3", 
    "Transition-Shape4", "Transition-Shape5", 
  };

  public UMLStateDiagramTemplate() {
  }

  public void initTools() {
    String[] temp = { ".State1", ".State2", ".State3", 
		      ".CompoundState1", ".CompoundState2",
		      ".OrthogonalState1", ".OrthogonalState1" }; 
    for (int i = 0; i < temp.length; i++) { 
      addNodeToolNames(name + temp[i],  stateNodeEdgeToolNames);
    }

    addNodeToolNames(name + ".InitialState", initStateNodeEdgeToolNames);
    addNodeToolNames(name + ".FinalState", finalStateNodeEdgeToolNames);
    addNodeToolNames(name + ".EntryState", initStateNodeEdgeToolNames);
    addNodeToolNames(name + ".ExitState", finalStateNodeEdgeToolNames);
    addNodeToolNames(name + ".DeepHistoryState", initStateNodeEdgeToolNames);
    addNodeToolNames(name + ".ShallowHistoryState", initStateNodeEdgeToolNames);

    String[] transTemp = { ".Transition1", ".Transition2", ".Transition3", 
			   ".Transition4", ".Transition5", ".Transition6", 
			   ".Transition7", ".Transition8", ".Transition9",
			   ".Transition10", ".Transition11" }; 
    for (int i = 0; i < transTemp.length; i++) { 
      addEdgeToolNames(name + transTemp[i], transEdgeShapeNames);
    }
  }

  public String[][] getGapToolNames() { 
    return stateDiagramGapToolNames;
  }

  @Override
  public void makeTemplate(Map iconMap) {
    UMLStateUtil.initStyle(iconMap, this);

    // add state machine state
    addStateMachineTemplate("StateMachine", 300, 200);

    // a simple state (small)
    if (isClassicTemplate()) { 
      addSimpleStateTemplate("State1", false, 70, 20);
      addSimpleStateTemplate("State2", true, 100, 50);
    }
    if (isModernTemplate()) { 
      addSimpleStateTemplate("State1" + MODERN_STYLE, false, true, 70, 20);
      addSimpleStateTemplate("State2" + MODERN_STYLE, true, true, 100, 50);

      SimpleStatementShape stmt = 
	makeElementShape(SimpleStatementShape.ACTION,  "Action", "action", OPER_FG, OPER_BG);
      add(new TemplateToolButton("Action", stmt, 36, 16, false, true));
    }

    // add submachine state
    addSubmachineStateTemplate("State3", 130, 40);

    // add hyper state
    if (isClassicTemplate()) { 
      addHyperStateTemplate("CompoundState1", false, 200, 200);
      addHyperStateTemplate("CompoundState2", true, 200, 200);
    }
    if (isModernTemplate()) { 
      addHyperStateTemplate("CompoundState1" + MODERN_STYLE, false, true, 200, 200);
      addHyperStateTemplate("CompoundState2" + MODERN_STYLE, true, true, 200, 200);
    }

    // add orthogonal state
    if (isClassicTemplate()) {     
      addOrthogonalStateTemplate("OrthogonalState1", false, 200, 200);
      addOrthogonalStateTemplate("OrthogonalState2", true, 200, 200);
    }
    if (isModernTemplate()) { 
      addOrthogonalStateTemplate("OrthogonalState1" + MODERN_STYLE, false, true, 200, 200);
      addOrthogonalStateTemplate("OrthogonalState2" + MODERN_STYLE, true, true, 200, 200);
    }

    // initial state
    addStateTemplate("InitialState", State.StateType.Initial_State, 10, 10, 15,	15);
    // final state
    addStateTemplate("FinalState", State.StateType.Final_State, 10, 10, 15, 15);

    // entry state
    addStateTemplate("EntryState", State.StateType.Entry_Point, 10, 10, 15, 15);
    // exit state
    addStateTemplate("ExitState", State.StateType.Exit_Point, 10, 10, 15, 15);

    // deep history state
    addStateTemplate("DeepHistory", State.StateType.Deep_History_State, 10, 10,	20, 20);
    // shallow history state
    addStateTemplate("ShallowHistory", State.StateType.Shallow_History_State,
		     10, 10, 20, 20);

    // junction state
    addStateTemplate("JunctionState", State.StateType.Junction_State, 0, 0, 20,	20);

    // choice state
    addStateTemplate("ChoiceState", State.StateType.Decision_State, 0, 0, 20, 20);

    // transitions
    LineShape line1 = new LineShape(0, 20, 50, 20);
    GraphEdgeShape line = new GraphEdgeShape(0, 20, 50, 20);
    addTransitionTemplate("Transition1", line, line1);

    QuadCurveShape qcurve1 = new QuadCurveShape(0, 24, 48, 0, 12, 0);
    GraphEdgeShape qcurve = new GraphEdgeShape(0, 24, 48, 0, 12, 0);
    addTransitionTemplate("Transition2", qcurve, qcurve1, 36, 24);

    CubicCurveShape curve1 = new CubicCurveShape(0, 24, 48, 24, 12, 0, 36, 0);
    GraphEdgeShape curve = new GraphEdgeShape(0, 24, 48, 24, 12, 0, 36, 0);
    curve.setCurveType(CubicCurveShape.C_SHAPE_CURVE);
    addTransitionTemplate("Transition10", curve, curve1);

    curve1 = new CubicCurveShape(0, 48, 48, 0, 36, 36, 12, 12);
    curve = new GraphEdgeShape(0, 48, 48, 0, 36, 36, 12, 12);
    addTransitionTemplate("Transition3", curve, curve1);

    
    PolyCurveSelfLoop ploop1 = new PolyCurveSelfLoop(0, 24, 24, 48, 28, 28, 
						    ShapeConstants.NORTH_EAST);
    ploop1.calculateBounds();
    GraphEdgeShape ploop = new  GraphEdgeShape(false, false, 
					       0, 24, 24, 48, 28, 28, 
					       ShapeConstants.NORTH_EAST);
    addTransitionTemplate("Transition4", ploop, ploop1);
    
    CubicCurveSelfLoop cloop1 = new CubicCurveSelfLoop(0, 50, 30, 50, 30,
						       ShapeConstants.NORTH);
    GraphEdgeShape cloop = new  GraphEdgeShape(false, true, 
					       0, 50, 30, 50, 0, 30,
					       ShapeConstants.NORTH);
    addTransitionTemplate("Transition5", cloop, cloop1);

    OrthogonalLineShape oline = new OrthogonalLineShape(false, 50, 0);
    oline.addPoint(0, 50);
    oline.addPoint(50, 100);
    oline.setRoundCorner(true);
    oline.calculateBounds();
    GraphEdgeShape oedge = new GraphEdgeShape(false, 50, 0);
    oedge.setAllowSelfLoop(true);
    oedge.addPoint(0, 50);
    oedge.addPoint(50, 100);
    oedge.setRoundCorner(true);
    oedge.calculateBounds();
    addTransitionTemplate("Transition6", oedge, oline, 36, 30);

    oline = new OrthogonalLineShape(0, 50);
    oline.addPoint(50, 0);
    oline.addPoint(100, 50);
    oline.setRoundCorner(true);
    oline.calculateBounds();
    oedge = new GraphEdgeShape(true, 0, 50);
    oedge.setAllowSelfLoop(true);
    oedge.addPoint(50, 0);
    oedge.addPoint(100, 50);
    oedge.setRoundCorner(true);
    oedge.calculateBounds();
    addTransitionTemplate("Transition7", oedge, oline);

    oline = new OrthogonalLineShape(0, 80);
    oline.addPoint(100, 20);
    oline.setRoundCorner(true);
    oline.calculateBounds();
    oedge = new GraphEdgeShape(true, 0, 80);
    oedge.addPoint(100, 20);
    oedge.setRoundCorner(true);
    oedge.calculateBounds();
    addTransitionTemplate("Transition8", oedge, oline);

    oline = new OrthogonalLineShape(false, 0, 80);
    oline.addPoint(80, 0);
    oline.setRoundCorner(true);
    oline.calculateBounds();
    oedge = new GraphEdgeShape(false, 0, 80);
    oedge.addPoint(80, 0);
    oedge.setRoundCorner(true);
    oedge.calculateBounds();
    addTransitionTemplate("Transition9", oedge, oline);

    PolyCurveShape pcurve = new PolyCurveShape(0, 0);
    pcurve.addPoint(25, 40);
    pcurve.addPoint(55, 0);
    pcurve.addPoint(80, 40);
    pcurve.adjustControlPoints();
    pcurve.calculateBounds();
    GraphEdgeShape cedge = new GraphEdgeShape(GraphEdgeShape.POLY_CURVE, false);
    cedge.setFirst(0, 0);
    cedge.addPoint(25, 40);
    cedge.addPoint(55, 0);
    cedge.addPoint(80, 40);
    cedge.adjustControlPoints();
    cedge.calculateBounds();
    addTransitionTemplate("Transition11", cedge, pcurve);

    // notes
    addNotesTemplate("Notes1", true, "Link");
    addNotesTemplate("Notes2", false);

    // link
    addNotesLinkTemplate("Link", new LineShape(0, 20, 50, 20));

    makeNodeEdgePopupTemplates();
    makeEdgeShapeTemplates();
  }

  protected void makeNodeEdgePopupTemplates() { 
    LineShape line1 = new LineShape(10, 40, 10, 0);
    addTransitionTemplate("Transition1-1-Popup", "Transition1", line1, 16, 20, false, 
			  TRANSITION_COLOR, TemplateToolButton.POPUP_BUTTON);
    line1 = new LineShape(10, 0, 10, 40);
    addTransitionTemplate("Transition1-2-Popup", "Transition1", line1, 16, 20, true, 
			  TRANSITION_COLOR, TemplateToolButton.POPUP_BUTTON);
    line1 = new LineShape(10, 40, 10, 0);
    addTransitionTemplate("Transition1-3-Popup", "Transition1", line1, 16, 20, true, 
			  TRANSITION_COLOR, TemplateToolButton.POPUP_BUTTON);
    line1 = new LineShape(10, 0, 10, 40);
    addTransitionTemplate("Transition1-4-Popup", "Transition1", line1, 16, 20, false, 
			  TRANSITION_COLOR, TemplateToolButton.POPUP_BUTTON);

    line1 = new LineShape(0, 10, 40, 10);
    addTransitionTemplate("Transition1-5-Popup", "Transition1", line1, 25, 10, true, 
			  TRANSITION_COLOR, TemplateToolButton.POPUP_BUTTON);
    line1 = new LineShape(40, 10, 0, 10);
    addTransitionTemplate("Transition1-6-Popup", "Transition1", line1, 25, 10, false, 
			  TRANSITION_COLOR, TemplateToolButton.POPUP_BUTTON);
    line1 = new LineShape(0, 10, 40, 10);
    addTransitionTemplate("Transition1-7-Popup", "Transition1", line1, 25, 10, false, 
			  TRANSITION_COLOR, TemplateToolButton.POPUP_BUTTON);
    line1 = new LineShape(40, 10, 0, 10);
    addTransitionTemplate("Transition1-8-Popup", "Transition1", line1, 25, 10, true, 
			  TRANSITION_COLOR, TemplateToolButton.POPUP_BUTTON);

    QuadCurveShape qcurve1 = new QuadCurveShape(0, 48, 24, 0, 0, 12);
    addTransitionTemplate("Transition2-1-Popup", "Transition2", qcurve1, 16, 20, false, 
			  TRANSITION_COLOR, TemplateToolButton.POPUP_BUTTON);
    qcurve1 = new QuadCurveShape(0, 0, 24, 48, 24, 12);
    addTransitionTemplate("Transition2-2-Popup", "Transition2", qcurve1, 16, 20, true, 
			  TRANSITION_COLOR, TemplateToolButton.POPUP_BUTTON);
    qcurve1 = new QuadCurveShape(0, 48, 24, 0, 0, 12);
    addTransitionTemplate("Transition2-3-Popup", "Transition2", qcurve1, 16, 20, true, 
			  TRANSITION_COLOR, TemplateToolButton.POPUP_BUTTON);
    qcurve1 = new QuadCurveShape(0, 0, 24, 48, 24, 12);
    addTransitionTemplate("Transition2-4-Popup", "Transition2", qcurve1, 16, 20, false, 
			  TRANSITION_COLOR, TemplateToolButton.POPUP_BUTTON);

    qcurve1 = new QuadCurveShape(0, 24, 48, 0, 12, 0);
    addTransitionTemplate("Transition2-5-Popup", "Transition2", qcurve1, 24, 12, true, 
			  TRANSITION_COLOR, TemplateToolButton.POPUP_BUTTON);
    qcurve1 = new QuadCurveShape(48, 24, 0, 0, 36, 0);
    addTransitionTemplate("Transition2-6-Popup", "Transition2", qcurve1, 24, 12, false, 
			  TRANSITION_COLOR, TemplateToolButton.POPUP_BUTTON);
    qcurve1 = new QuadCurveShape(0, 24, 48, 0, 12, 0);
    addTransitionTemplate("Transition2-7-Popup", "Transition2", qcurve1, 24, 12, false, 
			  TRANSITION_COLOR, TemplateToolButton.POPUP_BUTTON);
    qcurve1 = new QuadCurveShape(48, 24, 0, 0, 36, 0);
    addTransitionTemplate("Transition2-8-Popup", "Transition2", qcurve1, 24, 12, true, 
			  TRANSITION_COLOR, TemplateToolButton.POPUP_BUTTON);
  }

  protected void makeEdgeShapeTemplates() { 
    // transition edge shape template 
    LineShape line1 = new LineShape(0, 20, 50, 20);
    addTransitionShapeTemplate("Transition-Shape1", line1, TRANSITION_COLOR, 25, 10);

    QuadCurveShape qcurve1 = new QuadCurveShape(0, 24, 48, 0, 12, 0);
    addTransitionShapeTemplate("Transition-Shape2", qcurve1, TRANSITION_COLOR, 25, 10);
    
    CubicCurveShape curve1 = new CubicCurveShape(0, 24, 48, 24, 12, 0, 36, 0);
    addTransitionShapeTemplate("Transition-Shape3", curve1, TRANSITION_COLOR, 25, 10);

    OrthogonalLineShape oline = new OrthogonalLineShape(0, 50);
    oline.addPoint(50, 0);
    oline.addPoint(100, 50);
    oline.setRoundCorner(true);
    oline.calculateBounds();
    addTransitionShapeTemplate("Transition-Shape4", oline, TRANSITION_COLOR, 25, 10);

    PolyCurveShape pcurve = new PolyCurveShape(0, 0);
    pcurve.addPoint(30, 40);
    pcurve.addPoint(70, 0);
    pcurve.addPoint(100, 40);
    pcurve.adjustControlPoints();
    pcurve.calculateBounds();
    addTransitionShapeTemplate("Transition-Shape5", pcurve, TRANSITION_COLOR, 25, 10);
  }

  protected void addStateMachineTemplate(String tempName, float w, float h) {
    // CompoundStateShape shape, iconShape;
    GraphNodeBase shape, iconShape;
    iconShape = new CompoundStateShape(0, 0, w, h, false, true, false);
    shape = new CompoundStateShape(0, 0, w, h, false, true, false);

    setNodeAttr(shape);
    setNodeColor(shape, STATE_FG, STATE_MACHINE_BG);
    setNodeAttr(iconShape);
    setNodeColor(iconShape, STATE_FG, STATE_MACHINE_BG);

    TextShape text = makeTitleText("StateMachine", STATE_NAME_FONT,
				   STATE_NAME_COLOR);
    text.setDisplayName("Name");
    text.setAllowRotation(false);
    TextShape stereotype = makeContentText(null, "stereotype", "\u00AB", "\u00BB", true, 
					   STEREOTYPE_FONT, STEREOTYPE_COLOR);
    BoxLabel header = UMLUtil.makeHeader(text, stereotype);
    shape.setLabel(DrawShapeConstants.ROLE_NODE_TITLE_LABEL, header);

    shape.setAcceptSubshape(true);
    shape.setScaleMode(DrawShapeConstants.SCALE_EXCLUDE_SUBSHAPE);

    State state = new StateMachine();
    shape.setModel(state);
    shape.setModelListener(new UMLStateModelListener());

    add(new TemplateToolButton(tempName, shape, iconShape, 36, 30, false, true));

  }

  protected void addSimpleStateTemplate(String tempName, 
					boolean showAction,
					float w, float h) {
    addSimpleStateTemplate(tempName, showAction, false, w, h);
  }

  protected void addSimpleStateTemplate(String tempName, 
					boolean showAction,
					boolean useBlock,
					float w, float h) {
    SimpleStateShape shape, iconShape;
    if (showAction) {
      float[] divs = new float[] { 0.4f };
      shape = new SimpleStateShape(0, 0, w, h, divs);
      iconShape = new SimpleStateShape(0, 0, w, h, divs);
    } else {
      shape = new SimpleStateShape(0, 0, w, h);
      iconShape = new SimpleStateShape(0, 0, w, h);
    }

    setNodeAttr(iconShape);
    setNodeColor(iconShape, STATE_FG, STATE_BG);
    setNodeAttr(shape);
    setNodeColor(shape, STATE_FG, STATE_BG);

    TextShape text = makeTitleText("State", STATE_NAME_FONT, STATE_NAME_COLOR);
    text.setDisplayName("Name");
    text.setAllowRotation(false);

    TextShape stereotype = makeContentText(null, "stereotype", "\u00AB",
					   "\u00BB", true, STEREOTYPE_FONT, STEREOTYPE_COLOR);

    BoxLabel header;
    if (allowMultiLineName) {
      BoxLabel box = new BoxLabel(VERTICAL, CENTER);
      box.addShape(text);
      text.setAllowMultiLine(true);
      header = UMLUtil.makeHeader(box, stereotype);
    } else {
      header = UMLUtil.makeHeader(text, stereotype);
    }

    // shape.setLabel(DrawShape.ROLE_NODE_LABEL, header);
    shape.setLabel(DrawShapeConstants.ROLE_NODE_TITLE_LABEL, header);

    shape.setAcceptSubshape(false);
    shape.setScaleMode(DrawShapeConstants.SCALE_EXCLUDE_SUBSHAPE);

    State state = new State(State.StateType.Simple_State);
    shape.setModel(state);
    shape.setModelListener(new UMLStateModelListener());

    DrawShape action;
    if (useBlock) { 
      //action = makeActionListShape();
      action = makeBlockShape(BlockShape.ACTION_LIST, SimpleStatementShape.ACTION,
			      OPER_FG, OPER_BG, "Action", "action");
    } else { 
      action = makeContentGroup("action", null, null, ACTION_FONT, ACTION_COLOR);
    }
    shape.initAction(action);
    shape.fitCompartments();
    //shape.doLayout();

    int iconWidth = 36, iconHeight = 30;
    add(new TemplateToolButton(tempName, shape, iconShape, iconWidth, iconHeight, 
			       false, true));
  }
  
  protected void addSubmachineStateTemplate(String tempName, float w, float h) {
    SimpleStateShape shape, iconShape;
    shape = new SimpleStateShape(0, 0, w, h);
    iconShape = new SimpleStateShape(0, 0, w, h);

    setNodeAttr(iconShape);
    setNodeColor(iconShape, STATE_FG, STATE_BG);
    setNodeAttr(shape);
    setNodeColor(shape, STATE_FG, STATE_BG);

    TextShape text = makeTitleText("Name : Submachine", 
				   STATE_NAME_FONT, STATE_NAME_COLOR);
    text.setDisplayName("Submachine");
    text.setAllowRotation(false);
    TextShape stereotype = makeContentText(null, "stereotype", "\u00AB", "\u00BB", true, 
					   STEREOTYPE_FONT, STEREOTYPE_COLOR);
    BoxLabel header = UMLUtil.makeHeader(text, stereotype);
    // shape.setLabel(DrawShape.ROLE_NODE_LABEL, header);
    shape.setLabel(DrawShapeConstants.ROLE_NODE_TITLE_LABEL, header);

    shape.setAcceptSubshape(true);
    shape.setScaleMode(DrawShapeConstants.SCALE_EXCLUDE_SUBSHAPE);

    State state = new SubmachineState();
    shape.setModel(state);
    shape.setModelListener(new UMLStateModelListener());

    BoxLabel action;
    action = makeContentGroup("action", null, null, ACTION_FONT, ACTION_COLOR);
    shape.initAction(action);
    shape.doLayout();

    int iconWidth = 36, iconHeight = 30;
    add(new TemplateToolButton(tempName, shape, iconShape, iconWidth, iconHeight, 
			       false, true));
  }

  protected void addHyperStateTemplate(String tempName, 
				       boolean showAction,
				       float w, float h) {
    addHyperStateTemplate(tempName, showAction, false, w, h);
  }

  protected void addHyperStateTemplate(String tempName, 
				       boolean showAction,
				       boolean useBlock,
				       float w, float h) {
    CompoundStateShape shape, iconShape;
    iconShape = new CompoundStateShape(0, 0, w, h, showAction, false);
    shape = new CompoundStateShape(0, 0, w, h, showAction, false);

    setNodeAttr(iconShape);
    setNodeColor(iconShape, STATE_FG, COMPOUND_STATE_BG);
    setNodeAttr(shape);
    setNodeColor(shape, STATE_FG, COMPOUND_STATE_BG);

    TextShape text = makeTitleText("State", STATE_NAME_FONT, STATE_NAME_COLOR);
    text.setDisplayName("Name");
    text.setAllowRotation(false);
    TextShape stereotype = makeContentText(null, "stereotype", "\u00AB",
					   "\u00BB", true, STEREOTYPE_FONT, STEREOTYPE_COLOR);
    BoxLabel header = UMLUtil.makeHeader(text, stereotype);
    shape.setLabel(DrawShapeConstants.ROLE_NODE_TITLE_LABEL, header);

    shape.setAcceptSubshape(true);
    shape.setScaleMode(DrawShapeConstants.SCALE_EXCLUDE_SUBSHAPE);

    State state = new HyperState();
    shape.setModel(state);
    shape.setModelListener(new UMLStateModelListener());

    DrawShape action;
    if (useBlock) { 
      //action = makeElementShape(SimpleStatementShape.ACTION,  "Action", "action", OPER_FG, OPER_BG);
      action = makeBlockShape(BlockShape.ACTION_LIST, SimpleStatementShape.ACTION,
			      OPER_FG, OPER_BG, "Action", "action");
    } else { 
      action = makeContentGroup("action", null, null, ACTION_FONT, ACTION_COLOR);
    }
    shape.initAction(action);
    //shape.doLayout();

    int iconWidth = 36, iconHeight = 30;
    add(new TemplateToolButton(tempName, shape, iconShape, iconWidth, iconHeight, false, true));
  }

  protected void addOrthogonalStateTemplate(String tempName,
					    boolean showAction, 
					    float w, float h) {
    addOrthogonalStateTemplate(tempName, showAction, false, w, h);
  }

  protected void addOrthogonalStateTemplate(String tempName,
					    boolean showAction, 
					    boolean useBlock,
					    float w, float h) {
    OrthogonalStateShape shape, iconShape;
    iconShape = new OrthogonalStateShape(0, 0, w, h, showAction, false);
    shape = new OrthogonalStateShape(0, 0, w, h, showAction, false);

    setNodeAttr(iconShape);
    setNodeColor(iconShape, STATE_FG, ORTHOGONAL_STATE_BG);
    setNodeAttr(shape);
    setNodeColor(shape, STATE_FG, ORTHOGONAL_STATE_BG);

    TextShape text = makeTitleText("State", STATE_NAME_FONT, STATE_NAME_COLOR);
    text.setDisplayName("Name");
    text.setAllowRotation(false);
    TextShape stereotype = makeContentText(null, "stereotype", "\u00AB", "\u00BB", 
					   true, STEREOTYPE_FONT, STEREOTYPE_COLOR);
    BoxLabel header = UMLUtil.makeHeader(text, stereotype);
    shape.setLabel(DrawShapeConstants.ROLE_NODE_TITLE_LABEL, header);

    shape.setAcceptSubshape(true);
    shape.setScaleMode(DrawShapeConstants.SCALE_EXCLUDE_SUBSHAPE);

    State state = new OrthogonalState();
    shape.setModel(state);
    shape.setModelListener(new UMLStateModelListener());

    DrawShape action;
    if (useBlock) { 
      //action = makeElementShape(SimpleStatementShape.ACTION,  "Action", "action", OPER_FG, OPER_BG);
      action = makeBlockShape(BlockShape.ACTION_LIST, SimpleStatementShape.ACTION,
			      OPER_FG, OPER_BG, "Action", "action");
    } else { 
      action = makeContentGroup("action", null, null, ACTION_FONT, ACTION_COLOR);
    }
    shape.initAction(action);
    //shape.doLayout();

    int iconWidth = 36, iconHeight = 30;
    add(new TemplateToolButton(tempName, shape, iconShape, iconWidth, iconHeight, 
			       false, true));
  }

  protected void addStateTemplate(String tempName, State.StateType type,
				  float x, float y, float w, float h) {
    addStateTemplate(tempName, type, false, x, y, w, h);
  }

  protected void addStateTemplate(String tempName, State.StateType type,
				  boolean titled, float x, float y, float w, float h) {
    GraphNodeBase shape = null;
    CompartmentalRoundRectangleShape cshape = null;
    DrawShape iconShape = null;
    TextShape text = null;
    CompoundDrawShape comp = null;
    DrawShape s1;
    int iconWidth = 36, iconHeight = 18;
    float x1, y1, w1, h1;
    int role = DrawShapeConstants.ROLE_NODE_LABEL;
    switch (type) {
    case State_Machine:
      addStateMachineTemplate(tempName, w, h);
      return;

    case Simple_State:
      addSimpleStateTemplate(tempName, false, w, h);
      return;

    case Hyper_State:
      addHyperStateTemplate(tempName, false, w, h);
      return;

    case Submachine_State:
      addSubmachineStateTemplate(tempName, w, h);
      return;

    case Orthogonal_State:
      addOrthogonalStateTemplate(tempName, false, w, h);
      return;

    case Initial_State:
    case Final_State:
    case Shallow_History_State:
    case Deep_History_State:
    case Decision_State:
    case Junction_State:
    case Entry_Point:
    case Exit_Point:
    case Terminate_Point:
      iconWidth = 36; 
      iconHeight = 18;
      switch (type) {
      case Initial_State:
	shape = new EllipseShape(x, y, x + w, y + h, true);
	shape.showBorder(false);
	setNodeAttr(shape);
	setNodeBgColor(shape, INITIAL_STATE_BG, true);
	break;
      case Final_State:
	shape = new EllipseShape(x, y, x + w, y + h);
	shape.setDeco(EllipseShape.DECO_DOT);
	setNodeAttr(shape);
	setNodeBgColor(shape, FINAL_STATE_BG, true);
	setPenColor(shape, FINAL_STATE_BG);
	shape.setFilled(false);
	break;
      case Shallow_History_State:
      case Deep_History_State:
	x1 = x + w * (type == State.StateType.Deep_History_State ? 0.15f : 0.3f);
	y1 = y + h * 0.75f;
	String hs = (type == State.StateType.Deep_History_State ? "H*" : "H");
	shape = new EllipseShape(x, y, x + w, y + h);
	setNodeAttr(shape);
	setNodeBgColor(shape, DEEP_HISTORY_STATE_BG, true);
	shape.addShape(setNodeAttr(new TextShape(x1, y1, hs)));

	comp = new CompoundDrawShape();
	comp.setName(tempName);
	comp.setAtomic(true);
	comp.addShape(setNodeAttr(s1 = new EllipseShape(x, y, x + w, y + h)));
	comp.addShape(setNodeAttr(new TextShape(x1, y1, hs)));
	setNodeBgColor(s1, DEEP_HISTORY_STATE_BG, true);
	comp.fitComponents();
	iconShape = comp;
	break;
      case Decision_State:
	shape = new RectangularShape(ShapeConstants.DIAMOND_SHAPE,
				     ShapeConstants.NORTH, x, y, x + w, y + h);
	shape.showBorder(false);
	setNodeAttr(shape);
	setNodeBgColor(shape, CHOICE_STATE_BG, true);
	break;
      case Junction_State:
	shape = new EllipseShape(x, y, x + w, y + h, true);
	shape.showBorder(false);
	setNodeAttr(shape);
	setNodeBgColor(shape, JUNCTION_STATE_BG, true);
	break;
      case Entry_Point:
	shape = new EllipseShape(x, y, x + w, y + h, true);
	setNodeAttr(shape);
	setNodeBgColor(shape, ENTRY_STATE_BG, true);
	shape.setOnBoundary(true);
	shape.setAllowLabelOutside(true);
	shape.setClipSubShapes(false);
	break;
      case Exit_Point:
	shape = new EllipseShape(x, y, x + w, y + h, true);
	shape.setDeco(EllipseShape.DECO_CROSS);
	setNodeAttr(shape);
	setNodeBgColor(shape, EXIT_STATE_BG, true);
	shape.setOnBoundary(true);
	shape.setAllowLabelOutside(true);
	shape.setClipSubShapes(false);
	break;
      case Terminate_Point:
	break;
      }
      shape.setFixedRatio(true);
      shape.setResizable(false);
      if (type == State.StateType.Entry_Point || 
	  type == State.StateType.Exit_Point) {
	shape.setAtomic(false);
      } else {
	shape.setAtomic(true);
      }
      shape.setAcceptSubshape(false);
      shape.setAllowEdgeOffset(false);
      break;
    }

    if (shape != null) {
      State state = null;
      switch (type) {
      case Hyper_State:
      case Submachine_State:
	state = new HyperState();
	break;
      case Orthogonal_State:
	state = new OrthogonalState();
	break;
      default:
	state = new State(type);
	break;
      }
      if (state != null) {
	shape.setModel(state);
	shape.setModelListener(new UMLStateModelListener());
      }
      if (iconShape != null) {
	add(new TemplateToolButton(tempName, shape, iconShape, iconWidth, iconHeight, false, true));
      } else {
	add(new TemplateToolButton(tempName, shape, iconWidth, iconHeight, false, true));
      }
    }
  }

  protected void addTransitionTemplate(String tempName, GraphEdgeBase shape) {
    addTransitionTemplate(tempName, shape, null);
  }

  protected void addTransitionTemplate(String tempName, GraphEdgeBase shape, DrawShape iconShape) {
    addTransitionTemplate(tempName, shape, iconShape, 36, 24);
  }

  protected void addTransitionTemplate(String tempName, GraphEdgeBase shape, 
				       DrawShape iconShape,
				       int iconWidth, int iconHeight) {
    if (shape != null) {
      // setLineAttr(shape, DrawAttr.SOLID_LINE, ArrowAttr.LINE_ARROW, 8,
      // 0, 0);
      setLineAttr(shape, DrawAttr.SOLID_LINE,
		  ArrowAttr.ArrowType.FilledTriangle, 8, null, 0);
      setPenColor(shape, TRANSITION_COLOR);

      GraphEdgeBase edge = (GraphEdgeBase) shape; 
      edge.setEdgeType(UMLTemplate.TRANSITION_EDGE);

      shape.setModel(new Transition());
      shape.setModelListener(new UMLTransitionModelListener(this));
      if (iconShape != null) { 
	setLineAttr(iconShape, DrawAttr.SOLID_LINE,
		    ArrowAttr.ArrowType.FilledTriangle, 8, null, 0);
	setPenColor(iconShape, TRANSITION_COLOR);
	add(new TemplateToolButton(tempName, shape, iconShape, iconWidth, iconHeight, false, true));
      } else { 
	add(new TemplateToolButton(tempName, shape, iconWidth, iconHeight, false, true));
      }
    }
  }

  protected void addTransitionTemplate(String tempName, 
				       String protoName, 
				       DrawShape iconShape,
				       int iconWidth, int iconHeight, 
				       boolean reverseEnds, 
				       String colorkey, 
				       int buttonType) {
    if (iconShape != null) { 
      setLineAttr(iconShape, DrawAttr.SOLID_LINE,
		  ArrowAttr.ArrowType.FilledTriangle, 8, null, 0);
      //setPenColor(iconShape, TRANSITION_COLOR);
      setPenColor(iconShape, colorkey);
      add(new TemplateToolButton(tempName, protoName, iconShape, iconWidth, iconHeight, false, true,
				 TemplateToolButton.DEFAULT_TOOL, reverseEnds, buttonType));
    }
  }

  protected void addTransitionShapeTemplate(String name, 
					    GraphEdgeBase edge, 
					    String colorkey,
					    int iconWidth, int iconHeight) {
    if (name != null && 
	edge != null) { 
      setLineAttr(edge, DrawAttr.SOLID_LINE, 
		  ArrowAttr.ArrowType.FilledTriangle, 8, null, 0);
      if (colorkey != null) {
	setPenColor(edge, colorkey);
      }
      addEdgeShapeTemplate(name, edge, iconWidth, iconHeight);
    }
  }

  protected boolean allowMultiLineName = true;

  public static final String STATE_MACHINE_BG = "template.UMLStateDiagram.StateMachine.bg";

  public static final String STATE_MACHINE_FG = "template.UMLStateDiagram.StateMachine.fg";

  public static final String STATE_FG = "template.UMLStateDiagram.State.fg";

  public static final String STATE_BG = "template.UMLStateDiagram.State.bg";

  public static final String COMPOUND_STATE_BG = "template.UMLStateDiagram.CompoundState.bg";

  public static final String ORTHOGONAL_STATE_BG = "template.UMLStateDiagram.OrthogonalState.bg";

  public static final String STATE_NAME_FONT = "template.UMLStateDiagram.StateName.font";

  public static final String STATE_NAME_COLOR = "template.UMLStateDiagram.StateName.color";

  public static final String TRANSITION_FONT = "template.UMLStateDiagram.Transition.font";

  public static final String TRANSITION_COLOR = "template.UMLStateDiagram.Transition.color";

  public static final String TRANSITION_TEXT_COLOR = "template.UMLStateDiagram.Transition.text.color";

  public static final String ACTION_FONT = "template.UMLStateDiagram.Action.font";

  public static final String ACTION_COLOR = "template.UMLStateDiagram.Action.color";

  public static final String INITIAL_STATE_BG = "template.UMLStateDiagram.InitialState.bg";

  public static final String ENTRY_STATE_BG = "template.UMLStateDiagram.EntryState.bg";

  public static final String EXIT_STATE_BG = "template.UMLStateDiagram.ExitState.bg";

  public static final String FINAL_STATE_BG = "template.UMLStateDiagram.FinalState.bg";

  public static final String HISTORY_STATE_BG = "template.UMLStateDiagram.HistoryState.bg";

  public static final String DEEP_HISTORY_STATE_BG = "template.UMLStateDiagram.DeepHistoryState.bg";

  public static final String JUNCTION_STATE_BG = "template.UMLStateDiagram.JunctionState.bg";

  public static final String CHOICE_STATE_BG = "template.UMLStateDiagram.ChoiceState.bg";

}
